import test from "ava"
import ceno from "../src"
import { HttpError, TimeoutError } from "../src"
import { createHttpTestServer } from "./helpers/create-http-test-server"
import { createLargeBlob } from "./helpers/create-large-file"

test('集成测试 - 基本 HTTP 方法组合', async (t) => {
    const server = await createHttpTestServer()

    // 设置路由
    server.get('/users', (req, res) => {
        res.json({ users: [{ id: 1, name: 'Alice' }] })
    })

    server.post('/users', (req, res) => {
        res.status(201).json({ id: 2, ...req.body })
    })

    server.put('/users/1', (req, res) => {
        res.json({ id: 1, ...req.body })
    })

    server.delete('/users/1', (req, res) => {
        res.status(204).send()
    })

    // 测试 GET
    const users = await ceno.get(server.url + '/users').json()
    t.deepEqual(users, { users: [{ id: 1, name: 'Alice' }] })

    // 测试 POST
    const newUser = await ceno.post(server.url + '/users', {
        json: { name: 'Bob', email: 'bob@example.com' }
    }).json()
    t.deepEqual(newUser, { id: 2, name: 'Bob', email: 'bob@example.com' })

    // 测试 PUT
    const updatedUser = await ceno.put(server.url + '/users/1', {
        json: { name: 'Alice Updated' }
    }).json()
    t.deepEqual(updatedUser, { id: 1, name: 'Alice Updated' })

    // 测试 DELETE
    const deleteResponse = await ceno.delete(server.url + '/users/1')
    t.is(deleteResponse.status, 204)

    await server.close()
})

test('集成测试 - 认证和自定义头部', async (t) => {
    const server = await createHttpTestServer()

    server.get('/protected', (req, res) => {
        const auth = req.headers.authorization
        const apiKey = req.headers['x-api-key']
        const userAgent = req.headers['user-agent']

        if (auth === 'Bearer secret-token' && apiKey === 'api-123' && userAgent === 'Ceno/1.0') {
            res.json({ success: true, user: 'authenticated' })
        } else {
            res.status(401).json({ error: 'Unauthorized' })
        }
    })

    // 成功认证
    const response = await ceno.get(server.url + '/protected', {
        headers: {
            'Authorization': 'Bearer secret-token',
            'X-API-Key': 'api-123',
            'User-Agent': 'Ceno/1.0'
        }
    }).json()
    
    t.deepEqual(response, { success: true, user: 'authenticated' })

    // 认证失败
    await t.throwsAsync(
        () => ceno.get(server.url + '/protected', {
            headers: { 'Authorization': 'Bearer wrong-token' }
        }).json(),
        { instanceOf: HttpError, message: /401/ }
    )

    await server.close()
})

test('集成测试 - 重试机制和错误恢复', async (t) => {
    let attemptCount = 0
    const server = await createHttpTestServer()

    server.get('/unstable', (req, res) => {
        attemptCount++
        if (attemptCount <= 2) {
            res.status(500).json({ error: 'Server Error', attempt: attemptCount })
        } else {
            res.json({ success: true, finalAttempt: attemptCount })
        }
    })

    const response = await ceno.get(server.url + '/unstable', {
        retry: {
            limit: 3,
            methods: ['get'],
            statusCodes: [500],
            delay: () => 50 // 快速重试用于测试
        }
    }).json()

    t.deepEqual(response, { success: true, finalAttempt: 3 })
    t.is(attemptCount, 3)

    await server.close()
})

test('集成测试 - 请求和响应拦截器链', async (t) => {
    const server = await createHttpTestServer()
    const requestLogs: string[] = []
    const responseLogs: string[] = []

    server.post('/intercepted', (req, res) => {
        res.json({ 
            received: req.body,
            timestamp: req.headers['x-timestamp']
        })
    })

    interface Result {
        received: {
            message: string
        }
        timestamp: string
    }

    const data = await ceno.post<Result>(server.url + '/intercepted', {
        json: { message: 'test' },
        interceptors: {
            request: [
                {
                    onFulfilled: (request) => {
                        requestLogs.push('interceptor-1')
                        request.headers.set('X-Interceptor-1', 'applied')
                        return request
                    }
                },
                {
                    onFulfilled: (request) => {
                        requestLogs.push('interceptor-2')
                        request.headers.set('X-Timestamp', new Date().toISOString())
                        return request
                    }
                }
            ],
            response: [
                {
                    onFulfilled: (response) => {
                        responseLogs.push('response-interceptor-1')
                        return response
                    }
                },
                {
                    onFulfilled: (response) => {
                        responseLogs.push('response-interceptor-2')
                        return response
                    }
                }
            ]
        }
    }).json()
    
    t.deepEqual(requestLogs, ['interceptor-1', 'interceptor-2'])
    t.deepEqual(responseLogs, ['response-interceptor-1', 'response-interceptor-2'])
    t.deepEqual(data.received, { message: 'test' })
    t.truthy(data.timestamp)

    await server.close()
})

// 修复超时和取消测试
test('集成测试 - 超时和请求取消', async (t) => {
    const server = await createHttpTestServer()

    server.get('/slow', (req, res) => {
        setTimeout(() => {
            res.json({ message: 'finally done' })
        }, 2000)
    })

    // 测试超时
    await t.throwsAsync(
        () => ceno.get(server.url + '/slow', { timeout: 100 }),
        { instanceOf: TimeoutError }
    )

    // 测试手动取消 - 修复 DOMException 处理
    const controller = new AbortController()
    setTimeout(() => controller.abort(), 50)

    try {
        await ceno.get(server.url + '/slow', { signal: controller.signal })
        t.fail('应该抛出取消错误')
    } catch (error) {
        // DOMException 在 Node.js 中不继承自 Error，所以需要特殊处理
        t.true(
            error.name === 'AbortError' || 
            error.constructor.name === 'DOMException' ||
            (error && typeof error === 'object' && 'name' in error),
            `期望取消错误，得到: ${error?.constructor?.name || typeof error}`
        )
    }

    await server.close()
})

test('集成测试 - 文件上传和 FormData', async (t) => {
    const server = await createHttpTestServer()

    server.post('/upload', (req, res) => {
        const contentType = req.headers['content-type']
        t.true(contentType?.includes('multipart/form-data'))
        
        // 模拟文件处理
        res.json({ 
            uploaded: true,
            contentType: contentType
        })
    })

    const formData = new FormData()
    formData.append('file', new Blob(['file content'], { type: 'text/plain' }), 'test.txt')
    formData.append('description', 'Test file upload')

    interface Result {
        uploaded: boolean
        contentType: string
    }

    const response = await ceno.post<Result>(server.url + '/upload', {
        body: formData
    }).json()

    t.true(response.uploaded)
    t.true(response.contentType.includes('multipart/form-data'))

    await server.close()
})

test('集成测试 - 搜索参数和 URL 构建', async (t) => {
    const server = await createHttpTestServer()

    server.get('/search', (req, res) => {
        res.json({ query: req.query })
    })

    interface Result {
        query: {
            q: string
            limit: string
            tags: string[]
            active: string
        }
    }

    // 使用 searchParams 选项
    const response1 = await ceno.get<Result>(server.url + '/search', {
        searchParams: {
            q: 'hello world',
            limit: 10,
            tags: 'javascript,typescript', // 改为字符串
            active: true
        }
    }).json()

    // 修复期望值
    t.deepEqual(response1.query, {
        q: 'hello world',
        limit: '10',
        tags: 'javascript,typescript', // 相应修改期望值
        active: 'true'
    })

    // 使用 prefixUrl
    const apiClient = ceno.extend({
        prefixUrl: server.url + '/api'
    })

    server.get('/api/users', (req, res) => {
        res.json({ endpoint: '/api/users' })
    })

    const response2 = await apiClient.get('users').json()
    t.deepEqual(response2, { endpoint: '/api/users' })

    await server.close()
})

test('集成测试 - 自定义 JSON 处理', async (t) => {
    const server = await createHttpTestServer()

    server.post('/json-custom', (req, res) => {
        res.json({ received: req.body })
    })

    // 自定义 JSON 序列化
    interface JsonCustomResult {
        received: {
            timestamp: Date
            value: number
        }
    }

    const response = await ceno.post<JsonCustomResult>(server.url + '/json-custom', {
        json: { 
            timestamp: new Date('2023-01-01'),
            value: 123
        },
        stringifyJson: (data) => JSON.stringify(data, (key, value) => {
            if (key === 'timestamp' && value instanceof Date) {
                return value.toISOString().split('T')[0]
            }
            return value
        }),
        parseJson: (text) => {
            const parsed = JSON.parse(text)
            // 自定义解析逻辑
            if (parsed.received && parsed.received.timestamp) {
                parsed.received.timestamp = new Date(parsed.received.timestamp)
            }
            return parsed
        }
    })

    const data = await response.json()
    t.is(data.received.timestamp instanceof Date, true)
    t.is(data.received.value, 123)

    await server.close()
})

test('集成测试 - 多种响应类型处理', async (t) => {
    const server = await createHttpTestServer()

    // JSON 响应
    server.get('/data.json', (req, res) => {
        res.json({ type: 'json', data: [1, 2, 3] })
    })

    // 文本响应  
    server.get('/data.txt', (req, res) => {
        res.type('text/plain').send('Hello, World!')
    })

    // 二进制响应
    server.get('/data.bin', (req, res) => {
        const buffer = Buffer.from([1, 2, 3, 4, 5])
        res.type('application/octet-stream').send(buffer)
    })

    // 测试不同响应类型
    const jsonData = await ceno.get(server.url + '/data.json').json()
    t.deepEqual(jsonData, { type: 'json', data: [1, 2, 3] })

    const textData = await ceno.get(server.url + '/data.txt').text()
    t.is(textData, 'Hello, World!')

    const binaryData = await ceno.get(server.url + '/data.bin').arrayBuffer()
    const uint8Array = new Uint8Array(binaryData)
    t.deepEqual(Array.from(uint8Array), [1, 2, 3, 4, 5])

    await server.close()
})

test('集成测试 - 完整的 API 工作流', async (t) => {
    const server = await createHttpTestServer()
    let userId = 1
    const users: any[] = []

    // 设置完整的 REST API
    server.post('/api/users', (req, res) => {
        const user = { id: ++userId, ...req.body, createdAt: new Date().toISOString() }
        users.push(user)
        res.status(201).json(user)
    })

    server.get('/api/users/:id', (req, res) => {
        const user = users.find(u => u.id === parseInt(req.params.id))
        if (user) {
            res.json(user)
        } else {
            res.status(404).json({ error: 'User not found' })
        }
    })

    server.put('/api/users/:id', (req, res) => {
        const userIndex = users.findIndex(u => u.id === parseInt(req.params.id))
        if (userIndex >= 0) {
            users[userIndex] = { ...users[userIndex], ...req.body, updatedAt: new Date().toISOString() }
            res.json(users[userIndex])
        } else {
            res.status(404).json({ error: 'User not found' })
        }
    })

    // 创建 API 客户端实例
    const apiClient = ceno.extend({
        prefixUrl: server.url + '/api',
        headers: {
            'Authorization': 'Bearer api-token',
            'Content-Type': 'application/json'
        },
        timeout: 5000,
        retry: {
            limit: 2,
            statusCodes: [500, 502, 503]
        },
        interceptors: {
            request: [{
                onFulfilled: (request) => {
                    request.headers.set('X-Request-ID', Math.random().toString(36))
                    return request
                }
            }],
            response: [{
                onFulfilled: (response) => {
                    // 不修改响应头，只记录日志或其他操作
                    console.log(`Response received at ${Date.now()}`)
                    return response
                }
            }]
        }
    })

    interface User {
        id: number
        name: string
        email: string
        createdAt?: string
        updatedAt?: string
    }

    // 完整工作流测试
    
    // 1. 创建用户
    const newUser = await apiClient.post<User>('users', {
        json: { name: 'John Doe', email: 'john@example.com' }
    }).json()
    
    t.is(newUser.name, 'John Doe')
    t.is(newUser.email, 'john@example.com')
    t.truthy(newUser.id)
    t.truthy(newUser.createdAt)

    // 2. 获取用户
    const fetchedUser = await apiClient.get<User>(`users/${newUser.id}`).json()
    t.deepEqual(fetchedUser, newUser)

    // 3. 更新用户
    const updatedUser = await apiClient.put<User>(`users/${newUser.id}`, {
        json: { name: 'John Updated' }
    }).json()
    
    t.is(updatedUser.name, 'John Updated')
    t.is(updatedUser.email, 'john@example.com') // 保持不变
    t.truthy(updatedUser.updatedAt)

    // 4. 处理不存在的用户
    await t.throwsAsync(
        () => apiClient.get('users/999').json(),
        { instanceOf: HttpError, message: /404/ }
    )

    await server.close()
})

test('集成测试 - 并发请求处理', async (t) => {
    const server = await createHttpTestServer()
    let requestCount = 0

    server.get('/concurrent/:id', (req, res) => {
        requestCount++
        const delay = Math.random() * 100 // 随机延迟
        setTimeout(() => {
            res.json({ 
                id: req.params.id, 
                requestNumber: requestCount,
                timestamp: Date.now()
            })
        }, delay)
    })

    // 并发发送 10 个请求
    interface ConcurrentResult {
        id: string
        requestNumber: number
        timestamp: number
    }

    const results = await Promise.all(
        Array.from({ length: 10 }, (_, i) => 
            ceno.get<ConcurrentResult>(server.url + `/concurrent/${i + 1}`).json()
        )
    )
    
    t.is(results.length, 10)
    t.is(requestCount, 10)
    
    // 验证所有请求都成功
    results.forEach((result, index) => {
        t.is(result.id, (index + 1).toString())
        t.truthy(result.requestNumber)
        t.truthy(result.timestamp)
    })

    await server.close()
})

test('集成测试 - 边界情况和错误恢复', async (t) => {
    const server = await createHttpTestServer()

    // 空响应处理
    server.get('/empty', (req, res) => {
        res.status(204).send()
    })

    // 大响应处理
    server.get('/large', (req, res) => {
        const largeData = { 
            items: Array.from({ length: 1000 }, (_, i) => ({
                id: i,
                data: 'x'.repeat(100)
            }))
        }
        res.json(largeData)
    })

    interface LargeResponse {
        items: {
            id: number
            data: string
        }[]
    }

    // 测试空响应
    const emptyResponse = await ceno.get(server.url + '/empty')
    t.is(emptyResponse.status, 204)
    const emptyText = await emptyResponse.text()
    t.is(emptyText, '')

    // 测试大响应
    const largeResponse = await ceno.get<LargeResponse>(server.url + '/large').json()
    t.is(largeResponse.items.length, 1000)
    t.is(largeResponse.items[0].data.length, 100)

    // 测试无效 URL - 使用 t.throws 而不是 t.throwsAsync
    t.throws(
        () => ceno.get('http://localhost:99999/nonexistent'),
        { name: 'TypeError', message: /Failed to parse URL/ }
    )

    await server.close()
})

test('集成测试 - 大文件上传测试', async (t) => {
    const server = await createHttpTestServer()

    server.post('/upload-large', (req, res) => {
        const contentLength = req.headers['content-length']
        const contentType = req.headers['content-type']
        
        // 验证接收到大文件
        t.true(parseInt(contentLength || '0') > 1024 * 1024) // 超过1MB
        t.true(contentType?.includes('multipart/form-data'))
        
        res.json({ 
            received: true,
            size: contentLength,
            type: 'large-file'
        })
    })

    // 创建5MB的大文件
    const largeBlob = createLargeBlob(5)
    const formData = new FormData()
    formData.append('largefile', largeBlob, 'large-test-file.bin')
    formData.append('description', '大文件上传测试')

    interface LargeUploadResult {
        received: boolean
        size: string
        type: string
    }

    const response = await ceno.post<LargeUploadResult>(server.url + '/upload-large', {
        body: formData,
        timeout: 30000 // 增加超时时间用于大文件
    }).json()

    t.true(response.received)
    t.is(response.type, 'large-file')
    t.true(parseInt(response.size) > 5 * 1024 * 1024) // 验证文件大小

    await server.close()
})

test('集成测试 - 文件上传进度监控', async (t) => {
    const server = await createHttpTestServer()
    const progressEvents: number[] = []

    server.post('/upload-progress', (req, res) => {
        // 模拟处理延迟
        setTimeout(() => {
            res.json({ processed: true })
        }, 100)
    })

    // 创建较大的文件用于测试进度
    const testBlob = createLargeBlob(2)
    const formData = new FormData()
    formData.append('file', testBlob, 'progress-test.bin')

    interface UploadProgressResult {
        processed: boolean
    }

    const response = await ceno.post<UploadProgressResult>(server.url + '/upload-progress', {
        body: formData,
        onUploadProgress: (progress) => {
            progressEvents.push(progress.percent)
        }
    }).json()

    t.true(response.processed)
    t.true(progressEvents.length > 0, '应该触发上传进度事件')
    t.true(progressEvents.some(p => p > 0), '进度应该大于0')

    await server.close()
})
